﻿namespace UnityEditor.Graphs.AnimationStateMachine
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using UnityEditor;
    using UnityEditor.Graphs;
    using UnityEditorInternal;
    using UnityEngine;

    internal class EdgeGUI : IEdgeGUI
    {
        private const float kArrowEdgeWidth = 2f;
        private const float kEdgeClickWidth = 10f;
        private const float kEdgeWidth = 5f;
        private Edge m_DraggingEdge;
        private static Slot s_TargetDraggingSlot;

        public EdgeGUI()
        {
            this.edgeSelection = new List<int>();
        }

        public void BeginSlotDragging(Slot slot, bool allowStartDrag, bool allowEndDrag)
        {
            this.EndDragging();
            Edge item = new Edge(slot, null);
            this.host.graph.edges.Add(item);
            this.m_DraggingEdge = item;
            this.smHost.tool.wantsMouseMove = true;
        }

        private void CreateTransition(UnityEditor.Graphs.AnimationStateMachine.Node fromNode, UnityEditor.Graphs.AnimationStateMachine.Node toNode)
        {
            StateNode node = toNode as StateNode;
            if (node != null)
            {
                UnityEditorInternal.State fromState = null;
                if (fromNode is StateNode)
                {
                    fromState = (fromNode as StateNode).state;
                }
                this.CreateTransition(fromState, node.state);
            }
            StateMachineNode node2 = toNode as StateMachineNode;
            if (node2 != null)
            {
                List<UnityEditorInternal.State> statesRecursive;
                StateMachine rootStateMachine;
                <CreateTransition>c__AnonStorey11 storey = new <CreateTransition>c__AnonStorey11 {
                    <>f__this = this,
                    fromStateNode = fromNode as StateNode
                };
                if (node2.stateMachine == this.smHost.stateMachineGraph.parentStateMachine)
                {
                    statesRecursive = this.smHost.stateMachineGraph.rootStateMachine.statesRecursive;
                    statesRecursive.RemoveAll(new Predicate<UnityEditorInternal.State>(storey.<>m__2B));
                    rootStateMachine = this.smHost.stateMachineGraph.rootStateMachine;
                }
                else
                {
                    rootStateMachine = node2.stateMachine;
                    statesRecursive = node2.stateMachine.statesRecursive;
                }
                List<StateMachine> stateMachinesRecursive = rootStateMachine.stateMachinesRecursive;
                stateMachinesRecursive.Add(rootStateMachine);
                GenericMenu menu = new GenericMenu();
                foreach (UnityEditorInternal.State state2 in statesRecursive)
                {
                    <CreateTransition>c__AnonStorey10 storey2 = new <CreateTransition>c__AnonStorey10 {
                        <>f__ref$17 = storey,
                        <>f__this = this
                    };
                    string name = state2.name;
                    storey2.currentParent = state2.GetStateMachine();
                    while ((storey2.currentParent != null) && (storey2.currentParent != rootStateMachine))
                    {
                        name = name.Insert(0, storey2.currentParent.name + "/");
                        storey2.currentParent = stateMachinesRecursive.Find(new Predicate<StateMachine>(storey2.<>m__2C));
                    }
                    menu.AddItem(new GUIContent(name), false, new GenericMenu.MenuFunction2(storey2.<>m__2D), state2);
                }
                menu.ShowAsContext();
            }
        }

        private void CreateTransition(UnityEditorInternal.State fromState, UnityEditorInternal.State toState)
        {
            StateMachine rootStateMachine = this.smHost.stateMachineGraph.rootStateMachine;
            Undo.RegisterUndo(rootStateMachine, "Transitions Added");
            rootStateMachine.AddTransition(fromState, toState);
            this.smHost.stateMachineGraph.RebuildGraph();
        }

        public void DoDraggedEdge()
        {
        }

        public void DoEdges()
        {
            if (Event.current.type == EventType.Repaint)
            {
                int num = 0;
                foreach (Edge edge in this.host.graph.edges)
                {
                    Texture2D image = (Texture2D) UnityEditor.Graphs.Styles.connectionTexture.image;
                    UnityEngine.Color selectedEdgeColor = edge.color;
                    bool flag = false;
                    for (int i = 0; (i < this.edgeSelection.Count) && !flag; i++)
                    {
                        if (this.edgeSelection[i] == num)
                        {
                            selectedEdgeColor = UnityEditor.Graphs.AnimationStateMachine.EdgeGUI.selectedEdgeColor;
                            flag = true;
                        }
                    }
                    this.DrawEdge(edge, image, selectedEdgeColor);
                    num++;
                }
            }
            if (this.IsDragging())
            {
                s_TargetDraggingSlot = null;
                Event.current.Use();
            }
            if (this.ShouldStopDragging())
            {
                this.EndDragging();
                Event.current.Use();
            }
        }

        private static void DrawArrow(UnityEngine.Color color, Vector3 cross, Vector3 direction, Vector3 center)
        {
            Vector3[] vectorArray;
            vectorArray = new Vector3[] { center + (direction * 5f), (center - (direction * 5f)) + (cross * 5f), (center - (direction * 5f)) - (cross * 5f), vectorArray[0] };
            UnityEngine.Color color2 = color;
            Shader.SetGlobalColor("_HandleColor", color2);
            HandleUtility.handleWireMaterial.SetPass(0);
            GL.Begin(4);
            GL.Color(color2);
            GL.Vertex(vectorArray[0]);
            GL.Vertex(vectorArray[1]);
            GL.Vertex(vectorArray[2]);
            GL.End();
            Handles.color = color;
            Handles.DrawAAPolyLine((Texture2D) UnityEditor.Graphs.Styles.connectionTexture.image, 2f, vectorArray);
        }

        private static void DrawArrows(UnityEngine.Color color, Vector3 cross, Vector3[] edgePoints, int numberOfArrows, EdgeDebugState state)
        {
            Vector3 vector = edgePoints[1] - edgePoints[0];
            Vector3 normalized = vector.normalized;
            Vector3 vector3 = ((Vector3) (vector * 0.5f)) + edgePoints[0];
            vector3 -= (Vector3) (cross * 0.5f);
            for (int i = 0; i < numberOfArrows; i++)
            {
                UnityEngine.Color red = color;
                if (state == EdgeDebugState.MuteAll)
                {
                    red = UnityEngine.Color.red;
                }
                else if (state == EdgeDebugState.SoloAll)
                {
                    red = UnityEngine.Color.green;
                }
                else if (i == 0)
                {
                    if ((state == EdgeDebugState.MuteSome) || (state == EdgeDebugState.MuteAndSolo))
                    {
                        red = UnityEngine.Color.red;
                    }
                    if (state == EdgeDebugState.SoloSome)
                    {
                        red = UnityEngine.Color.green;
                    }
                }
                else if ((i == 2) && (state == EdgeDebugState.MuteAndSolo))
                {
                    red = UnityEngine.Color.green;
                }
                Vector3 center = vector3 + ((Vector3) ((i * 13f) * normalized));
                DrawArrow(red, cross, normalized, center);
            }
        }

        private void DrawEdge(Edge edge, Texture2D tex, UnityEngine.Color color)
        {
            Vector3 vector;
            Vector3[] edgePoints = GetEdgePoints(edge, out vector);
            Handles.color = color;
            Vector3[] points = new Vector3[] { edgePoints[0], edgePoints[1] };
            Handles.DrawAAPolyLine(tex, 5f, points);
            EdgeInfo edgeInfo = this.smHost.stateMachineGraph.GetEdgeInfo(edge);
            int numberOfArrows = 1;
            if ((edgeInfo != null) && edgeInfo.hasMultipleTransitions)
            {
                numberOfArrows = 3;
            }
            EdgeDebugState normal = EdgeDebugState.Normal;
            if (edgeInfo != null)
            {
                normal = edgeInfo.debugState;
            }
            DrawArrows(color, vector, edgePoints, numberOfArrows, normal);
            if (this.smHost.liveLinkInfo.currentTransition != null)
            {
                Transition currentTransition = this.smHost.liveLinkInfo.currentTransition;
                if (edgeInfo.transitions.Find(new Predicate<Transition>(currentTransition.Equals)) != null)
                {
                    float currentTransitionProgress = this.smHost.liveLinkInfo.currentTransitionProgress;
                    if ((this.smHost.liveLinkInfo.currentTransition.GetSrcState() != null) && (this.smHost.liveLinkInfo.currentTransition.GetSrcState().GetStateMachine() != this.smHost.liveLinkInfo.currentTransition.GetDstState().GetStateMachine()))
                    {
                        currentTransitionProgress = (currentTransitionProgress % 0.5f) / 0.5f;
                    }
                    Handles.color = selectedEdgeColor;
                    Vector3[] vectorArray2 = new Vector3[] { edgePoints[0], (Vector3) ((edgePoints[1] * currentTransitionProgress) + (edgePoints[0] * (1f - currentTransitionProgress))) };
                    Handles.DrawAAPolyLine((float) 8f, vectorArray2);
                }
            }
        }

        public void EndDragging()
        {
            if (this.m_DraggingEdge != null)
            {
                this.host.graph.RemoveEdge(this.m_DraggingEdge);
                this.m_DraggingEdge = null;
                this.smHost.tool.Repaint();
            }
        }

        public void EndSlotDragging(Slot slot, bool allowMultiple)
        {
            if (((this.m_DraggingEdge != null) && (!(slot.node is StateMachineNode) || !(this.m_DraggingEdge.fromSlot.node is AnyStateNode))) && !(slot.node is AnyStateNode))
            {
                UnityEditor.Graphs.AnimationStateMachine.Node item = this.m_DraggingEdge.fromSlot.node as UnityEditor.Graphs.AnimationStateMachine.Node;
                UnityEditor.Graphs.AnimationStateMachine.Node node = slot.node as UnityEditor.Graphs.AnimationStateMachine.Node;
                if (slot == this.m_DraggingEdge.fromSlot)
                {
                    this.host.graph.RemoveEdge(this.m_DraggingEdge);
                }
                else
                {
                    this.m_DraggingEdge.toSlot = slot;
                    this.host.selection.Clear();
                    this.host.selection.Add(item);
                    Selection.activeObject = item.selectionObject;
                    this.CreateTransition(item, node);
                }
                this.m_DraggingEdge = null;
                s_TargetDraggingSlot = null;
                Event.current.Use();
                this.smHost.tool.wantsMouseMove = false;
                AnimatorControllerTool.tool.RebuildGraph();
            }
        }

        public Edge FindClosestEdge()
        {
            Edge edge = null;
            float positiveInfinity = float.PositiveInfinity;
            Vector3 mousePosition = (Vector3) Event.current.mousePosition;
            foreach (Edge edge2 in this.host.graph.edges)
            {
                Vector3[] edgePoints = GetEdgePoints(edge2);
                float num2 = HandleUtility.DistancePointLine(mousePosition, edgePoints[0], edgePoints[1]);
                if ((num2 < positiveInfinity) && (num2 < 10f))
                {
                    positiveInfinity = num2;
                    edge = edge2;
                }
            }
            return edge;
        }

        private static Vector3 GetEdgeEndPosition(Edge edge)
        {
            if (!IsEdgeBeingDragged(edge))
            {
                return GetNodeCenterFromSlot(edge.toSlot);
            }
            if (s_TargetDraggingSlot != null)
            {
                return GetNodeCenterFromSlot(s_TargetDraggingSlot);
            }
            return (Vector3) Event.current.mousePosition;
        }

        private static Vector3[] GetEdgePoints(Edge edge)
        {
            Vector3 vector;
            return GetEdgePoints(edge, out vector);
        }

        private static Vector3[] GetEdgePoints(Edge edge, out Vector3 cross)
        {
            Vector3[] vectorArray = new Vector3[] { GetEdgeStartPosition(edge), GetEdgeEndPosition(edge) };
            Vector3 vector = vectorArray[0] - vectorArray[1];
            cross = Vector3.Cross(vector.normalized, Vector3.forward);
            vectorArray[0] += (Vector3) (cross * 5f);
            if (!IsEdgeBeingDragged(edge))
            {
                vectorArray[1] += (Vector3) (cross * 5f);
            }
            return vectorArray;
        }

        private static Vector3 GetEdgeStartPosition(Edge edge)
        {
            return GetNodeCenterFromSlot(edge.fromSlot);
        }

        private static Vector3 GetNodeCenterFromSlot(Slot slot)
        {
            return (Vector3) slot.node.position.center;
        }

        private bool IsDragging()
        {
            return ((Event.current.type == EventType.MouseMove) && (this.m_DraggingEdge != null));
        }

        private static bool IsEdgeBeingDragged(Edge edge)
        {
            return (edge.toSlot == null);
        }

        private bool ShouldStopDragging()
        {
            return (((Event.current.type == EventType.KeyDown) && (Event.current.keyCode == KeyCode.Escape)) && (this.m_DraggingEdge != null));
        }

        public void SlotDragging(Slot slot, bool allowEndDrag, bool allowMultiple)
        {
            if (((this.m_DraggingEdge != null) && (!(slot.node is StateMachineNode) || !(this.m_DraggingEdge.fromSlot.node is AnyStateNode))) && !(slot.node is AnyStateNode))
            {
                s_TargetDraggingSlot = slot;
                Event.current.Use();
            }
        }

        public List<int> edgeSelection { get; set; }

        public UnityEditor.Graphs.GraphGUI host { get; set; }

        private static UnityEngine.Color selectedEdgeColor
        {
            get
            {
                return new UnityEngine.Color(0.42f, 0.7f, 1f, 1f);
            }
        }

        private UnityEditor.Graphs.AnimationStateMachine.GraphGUI smHost
        {
            get
            {
                return (this.host as UnityEditor.Graphs.AnimationStateMachine.GraphGUI);
            }
        }

        [CompilerGenerated]
        private sealed class <CreateTransition>c__AnonStorey10
        {
            internal UnityEditor.Graphs.AnimationStateMachine.EdgeGUI.<CreateTransition>c__AnonStorey11 <>f__ref$17;
            internal UnityEditor.Graphs.AnimationStateMachine.EdgeGUI <>f__this;
            internal StateMachine currentParent;

            internal bool <>m__2C(StateMachine sm)
            {
                return sm.IsDirectParent(this.currentParent);
            }

            internal void <>m__2D(object data)
            {
                this.<>f__this.CreateTransition(this.<>f__ref$17.fromStateNode.state, data as UnityEditorInternal.State);
            }
        }

        [CompilerGenerated]
        private sealed class <CreateTransition>c__AnonStorey11
        {
            internal UnityEditor.Graphs.AnimationStateMachine.EdgeGUI <>f__this;
            internal StateNode fromStateNode;

            internal bool <>m__2B(UnityEditorInternal.State s)
            {
                return this.<>f__this.smHost.stateMachineGraph.activeStateMachine.HasState(s);
            }
        }
    }
}

